#include "vthread.h"
#include "vmalloc.h"
#include <pthread.h>
#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>

#define THREAD_FLAGS_ISRUNNING  (1 << 0)
#define THREAD_FLAGS_ISDETACH   (1 << 1)
struct thread__
{
    pthread_t tid;
    pid_t pid;
    pthread_attr_t attr;
    int flags;
    vThreadFunc task;
    void *args;
};

vThread vThreadCreate(vThreadFunc func,void *args,int stack_size)
{
    return vThreadCreateWithPriority(func,args,stack_size,50);
}

void *inner_task(void *args)
{
    struct thread__ *th = (struct thread__ *)args;
    if(!th)
        return NULL;

    th->tid = pthread_self();
    th->pid = getpid();

    void *ret = th->task((vThread)th,th->args);

    th->flags &= ~THREAD_FLAGS_ISRUNNING;
    return ret;
}


vThread vThreadCreateWithPriority(vThreadFunc func, void *args, int stack_size, int priority)
{
    struct thread__ *thread = (struct thread__ *)vCalloc(1,sizeof(struct thread__));
    if(!thread)
        return NULL;

    thread->flags |= THREAD_FLAGS_ISRUNNING;
    thread->pid = 0;
    thread->tid = 0;
    thread->task = func;
    thread->args = args;
    pthread_attr_init(&thread->attr);
    if(stack_size > 0)
    {
        pthread_attr_setstacksize(&thread->attr,stack_size);
    }

    if(priority > 0)
    {
        pthread_attr_setschedpolicy(&thread->attr,SCHED_RR); /*调度策略*/
        struct sched_param param;
        pthread_attr_getschedparam(&thread->attr,&param);
        param.__sched_priority = priority;
        pthread_attr_setschedparam(&thread->attr,&param);
    }

    pthread_t tid;
    int ret = pthread_create(&tid,&thread->attr,inner_task,thread);
    if(ret != 0)
    {
        pthread_attr_destroy(&thread->attr);
        vFree(thread);
        return NULL;
    }
    return (vThread)thread;
}

int vThreadDestroy(vThread th)
{
    struct thread__ *thread = (struct thread__ *)th;
    if(!thread)
        return -1;

    if(thread->flags & THREAD_FLAGS_ISDETACH)
    {
        pthread_attr_destroy(&thread->attr);
        thread->flags &= ~THREAD_FLAGS_ISRUNNING;
        vFree(thread);
        return 0;
    }

    vThreadKill(th);
    pthread_join(thread->tid,NULL);
    return 0;
}

int lapi_thread_isrunning(vThread th)
{
    struct thread__ *thread = (struct thread__ *)th;
    if(thread)
    {
        return (thread->flags & THREAD_FLAGS_ISRUNNING) ? 1 : 0;
    }
    return 0;
}
void vThreadSetName(const char *name)
{
    prctl(PR_SET_NAME, name, 0, 0, 0);
}

int vThreadKill(vThread th)
{
    struct thread__ *thread = (struct thread__ *)th;
    if(!thread)
        return -1;
    /**
        需要等待tid有值时再kill
    printf("tid = %d\n",thread->tid);
    */
    return pthread_kill(thread->tid,SIGKILL);
}
int vThreadCancel(vThread th)
{
    struct thread__ *thread = (struct thread__ *)th;
    if(!thread)
        return -1;
    return pthread_cancel(thread->tid);
}
int vThreadDetach(vThread th)
{
    struct thread__ *thread = (struct thread__ *)th;
    if(!thread)
        return -1;

    pthread_detach(thread->tid);
    thread->flags |= THREAD_FLAGS_ISDETACH;
    return 0;
}

void vThreadSleep(int ms)
{
    usleep(ms * 1000);
}
